﻿using Library.Core.Application.IInfrastructure;
using Library.Core.Domain.Repository;
using Library.Core.Infrastructure.Common;
using Library.Core.Infrastructure.EntityFrameworkDataAccess;
using Library.Core.Infrastructure.EntityFrameworkDataAcceSynthetic.Extension;
using Microsoft.EntityFrameworkCore;
using Synthesize.BaseSet.Domain.Aggregation.Dtos.Authority.User;
using Synthesize.BaseSet.Domain.Aggregation.Entity.Authority;
using Synthesize.BaseSet.Domain.Repository.Authority;
using Synthesize.Infrastructure.PersistentObjects.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Synthesize.Infrastructure.Repository.Authority
{
    /// <summary>
    /// 用户基础类
    /// </summary>
    public class UserRepository : RepositoryBase<UserInfoEntity, UserInfo>, IUserRepository
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="currentUserInfo"></param>
        /// <param name="dbContext"></param>
        public UserRepository(ICurrentUserInfo currentUserInfo, IEFContext dbContext) : base(currentUserInfo, dbContext)
        {

        }

        /// <summary>
        /// 根据角色名称获取分页信息
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="specification"></param>
        /// <param name="orderExp"></param>
        /// <param name="inDto"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<PageData<GetUserListOutDto>> GetUserPageList(int pageIndex, int pageSize, Expression<Func<UserInfoEntity, bool>> specification,
                        (Expression<Func<GetUserListOutDto, dynamic>>, bool)[] orderExp, GetUserListInDto inDto, bool readOnly)
        {

            var result = new PageData<GetUserListOutDto>();

            var userIdList = new List<Guid>();
            if (inDto.DepartmentIds != null && inDto.DepartmentIds.Any())
            {
                userIdList = await GetAll<UserDepartmentRe>(readOnly: readOnly)
                   .Where(x => inDto.DepartmentIds.Contains(x.DepartmentId))
                   .Select(x => x.UserId)
                   .ToListAsync();
            }

            var pageData = GetAll(readOnly: readOnly)
                .Where(specification.ReplaceParameter<UserInfoEntity, UserInfo>())
                .WhereIf(inDto.DepartmentIds != null && inDto.DepartmentIds.Any(), x => userIdList.Contains(x.Id))
                .Select(x => new GetUserListOutDto()
                {
                    Id = x.Id,
                    Gender = x.Gender,
                    UserName = x.UserName,
                    Telphone = x.Telphone,
                    IsValid = x.IsValid,
                    IsSuperUser = x.IsSuperUser,
                    NickName = x.NickName,
                    PictureUrl = x.PictureUrl,
                    RealName = x.RealName,
                    Sort = x.Sort,
                    UserDescribe = x.UserDescribe,
                });
            if (orderExp.Any())
            {
                result = await pageData.ToPagedList(pageIndex, pageSize, orderExp);
            }
            else
            {
                result = await pageData.OrderBy(x => x.Sort).ToPagedList(pageIndex, pageSize);
            }

            if (result.Rows.Any())
            {
                var userIds = result.Rows.Select(x => x.Id).ToList();

                var roleQuery = GetAll<RoleInfo>(readOnly: readOnly);
                var userRoleData = await (
                       GetAll<UserRoleRe>(readOnly: readOnly)
                       .Where(x => userIds.Contains(x.UserId))
                    )
                    .GroupJoin(roleQuery, ur => ur.RoleId, r => r.Id, (ur, r) => new { ur, r })
                    .SelectMany(x => x.r.DefaultIfEmpty(), (x, r) => new { x.ur, r.Name })
                    .Select(x => new
                    {
                        x.ur.UserId,
                        x.ur.RoleId,
                        x.Name
                    }).ToListAsync();

                var departmentQuery = GetAll<DepartmentInfo>(readOnly: readOnly);
                var userDepartmentData = await (
                       GetAll<UserDepartmentRe>(readOnly: readOnly)
                       .Where(x => userIds.Contains(x.UserId))
                    )
                    .GroupJoin(departmentQuery, ud => ud.DepartmentId, d => d.Id, (ud, d) => new { ud, d })
                    .SelectMany(x => x.d.DefaultIfEmpty(), (x, d) => new { x.ud, d.Name })
                    .Select(x => new
                    {
                        x.ud.UserId,
                        x.ud.DepartmentId,
                        x.Name
                    }).ToListAsync();

                var postQuery = GetAll<PostInfo>(readOnly: readOnly);
                var userPostData = await (
                         GetAll<UserPostRe>(readOnly: readOnly)
                        .Where(x => userIds.Contains(x.UserId))
                    )
                    .GroupJoin(postQuery, up => up.PostId, p => p.Id, (up, p) => new { up, p })
                    .SelectMany(x => x.p.DefaultIfEmpty(), (x, p) => new { x.up, p.Name })
                    .Select(x => new
                    {
                        x.up.UserId,
                        x.up.PostId,
                        x.Name
                    }).ToListAsync();

                //拼装结果
                foreach (var item in result.Rows)
                {
                    var userRoles = userRoleData.Where(x => x.UserId == item.Id).ToList();
                    if (userRoles.Any())
                    {
                        item.RoleNames = string.Join(",", userRoles.Select(x => x.Name));
                        item.RoleIds = userRoles.Select(x => x.RoleId).ToList();
                    }

                    var userDepartment = userDepartmentData.FirstOrDefault(x => x.UserId == item.Id);
                    if (userDepartment!=null)
                    {
                        item.DepartmentName = userDepartment.Name;
                        item.DepartmentId = userDepartment.DepartmentId;
                    }

                    var userPosts = userPostData.Where(x => x.UserId == item.Id).ToList();
                    if (userPosts.Any())
                    {
                        item.PostNames = string.Join(",", userPosts.Select(x => x.Name));
                        item.PostIds = userPosts.Select(x => x.PostId).ToList();
                    }
                }
            }
            return result;
        }



        /// <summary>
        /// 根据条件获取用户列表信息
        /// </summary>
        /// <param name="input"></param>
        /// <param name="readOnly"></param>
        /// <returns></returns>
        public async Task<List<UserInfoEntity>> GetUserListByParameter(GetUserListByParameterInDto input, bool readOnly)
        {
            var result = new List<UserInfoEntity>();

            var userIdList = new List<Guid>();
            //角色Id
            if (input.RoleId.HasValue)
            {
                var userRoleReList = await GetAll<UserRoleRe>(readOnly: readOnly)
                        .Where(x => x.RoleId == input.RoleId.Value)
                        .ToListAsync();
                if (userRoleReList.Any())
                {
                    userIdList = userRoleReList.Select(x => x.UserId).ToList();
                }
            }

            //岗位Id
            if (input.PostId.HasValue)
            {
                var userPostReList = await GetAll<UserPostRe>(readOnly: readOnly)
                       .Where(x => x.PostId == input.PostId.Value)
                       .ToListAsync();
                if (userPostReList.Any())
                {
                    userIdList.AddRange(userPostReList.Select(x => x.UserId).ToList());
                }
            }

            //部门Id
            if (input.DepartmentId.HasValue)
            {
                var userDepartmentReList = await GetAll<UserDepartmentRe>(readOnly: readOnly)
                       .Where(x => x.DepartmentId == input.DepartmentId.Value)
                       .ToListAsync();
                if (userDepartmentReList.Any())
                {
                    userIdList.AddRange(userDepartmentReList.Select(x => x.UserId).ToList());
                }
            }
            
            var userList = await GetAll(readOnly: readOnly)
                            .WhereIf(input.RoleId.HasValue || input.PostId.HasValue || input.DepartmentId.HasValue, x => userIdList.Contains(x.Id))
                            .WhereIf(!string.IsNullOrEmpty(input.Keywords), x => input.Keywords.Contains(x.RealName) || input.Keywords.Contains(x.UserName) || input.Keywords.Contains(x.Telphone))
                            .ToListAsync();

            if (userList.Any())
            {
                result = userList.MapList<UserInfo, UserInfoEntity>();
            }
            return result;
        }
    }
}
